#ifndef __INI_SERIALIZABLE_H__
  #define __INI_SERIALIZABLE_H__

#include "serializable.h"
#include "ini.h"

//! An implementation for serializable, which uses an ini file as its storage media

/*!
Any object which is inherited from this class can save its state into a given ini file or load its member
variables from the given ini file.

Implementation date: 2008

Usage:

\code
class my_class : public ini_serializable {

private:
  string application_name;

public:

  const string &get_application_name() const {
    return this->application_name;
  }

  virtual void load() {
    DESERIALIZE(application_name);
  }

  virtual void persist(bool requires_lock = true) {
    SERIALIZE(application_name);
    ini_serializable::persist(requires_lock);
  }

  my_class() : ini_serializable("my_class", "my_ini_file.ini") {
    // nothing to do
  }

  virtual ~my_class() {
    // nothing to do
  }
};
\endcode
*/

class ini_serializable : public serializable {
private:
  ini_category ic;
  ini i;
  const char * const ini_file_name;

protected:
  //! serializes the given variable
  virtual void serialize(const string &variable_name, const bool value) {
    serialize(variable_name, (value == true) ? string("true") : string("false"));
  }

  //! serializes the given variable
  virtual void serialize(const string &variable_name, const int value) {
    string str_cnv;
    serialize(variable_name, converter::to_string(value, str_cnv));
  }

  //! serializes the given variable
  virtual void serialize(const string &variable_name, const long long value) {
    string str_cnv;
    serialize(variable_name, converter::to_string(value, str_cnv));
  }

  //! serializes the given variable
  virtual void serialize(const string &variable_name, const double value) {
    string str_cnv;
    serialize(variable_name, converter::to_string(value, str_cnv));
  }

  //! serializes the given variable
  virtual void serialize(const string &variable_name, const string &value) {
    ic.add_item(variable_name, value);
  }

  //! deserializes the given variable
  virtual void deserialize(bool &output, const string &variable_name) {
    string str_result;
    deserialize(str_result, variable_name);
    if (str_result == "true")
      output = true;
    else
      output = false;
  }

  //! deserializes the given variable
  virtual void deserialize(int &output, const string &variable_name) {
    string str_result;
    deserialize(str_result, variable_name);
    output = converter::to_int(str_result);
  }

  //! deserializes the given variable
  virtual void deserialize(long long &output, const string &variable_name) {
    string str_result;
    deserialize(str_result, variable_name);
    output = converter::to_long_long(str_result);
  }

  //! deserializes the given variable
  virtual void deserialize(double &output, const string &variable_name) {
    string str_result;
    deserialize(str_result, variable_name);
    output = converter::to_double(str_result);
  }

  //! deserializes the given variable
  virtual void deserialize(string &output, const string &variable_name) {
    if (loaded == false) {
      i.from_file(ini_file_name);
      loaded = true;
    }

    i.get_value(ic.get_category_name(), variable_name, output);
  }

  //! writes the data back to the ini file
  virtual void persist(bool requires_lock = true) {
    if (ic.get_items_count() == 0)
      return;

    i.clear();
    i.add_category(ic);
    i.to_file(ini_file_name);
    ic.clear();
    i.clear();
    loaded = false;
  }

  //! constructor
  ini_serializable(const char * const class_name, const char * const ini_file_name) : serializable(class_name), ini_file_name(ini_file_name) {
    ic.set_category_name(class_name);
  }

  //! destructor
  virtual ~ini_serializable() {
    // nothing to do
  }

public:

};

#endif
